/**
 * T extends U ? X : Y
 * 上面的类型表示：若 T 能够分配（赋值）给 U，那么类型是 X，否则为 Y，有点类似于JavaScript中的三元条件运算符。
 */
type foo<T> = T

let myFoo:foo<string> = 'my foo'
let myBool:foo<boolean> = false

type StrFoo<T extends string> = T

let aa:StrFoo<string> = 'bbb'

type StrFooLetter<T extends string = 'AA'> = T
let AA:StrFooLetter = 'AA'
let BB:StrFooLetter<'BB'> = 'BB'

type EnumStr = 'aa'|'bb'
type TExtEnumStr<T extends EnumStr> = T
let tExt:TExtEnumStr<'aa'> = 'aa'
let tExt2: TExtEnumStr<'bb'> = 'bb'



type IsNumber<N> = N extends number ? 'yes, is a number' : 'no, not a number';

let num:IsNumber<2> = 'yes, is a number'
let num2:IsNumber<true> = 'no, not a number'

type num = 2
type result1 = IsNumber<num>;
type hello = 'hello'
type result2 = IsNumber<hello> 


declare function f<T extends boolean>(x: T): T extends true ? string : number;
// Type is 'string | number'
let x = f(Math.random() < 0.5)
// Type is 'number'
let y = f(false)
// Type is 'string'
let z = f(true)

interface Foo {
  propA: boolean;
  propB: boolean;
}

declare function f<T>(x: T): T extends Foo ? string : number;

function foo<U>(x: U) {
  // 因为 ”x“ 未知，因此判断条件不足，不能确定条件分支，推迟条件判断直到 ”x“ 明确，
  // 推迟过程中，”a“ 的类型为分支条件类型组成的联合类型，
  // string | number
  let a = f(x);

  // 这么做是完全可以的
  let b: string | number = a;
}
/**
 * Exclude from T those types that are assignable to U
 * type Exclude<T, U> = T extends U ? never : T;
 */

 type AAType = 'aa'
 
 type neverType = Exclude<AAType, string> //never
 type strType =  Exclude<string, AAType> //string
 
 // 裸类型参数,没有被任何其他类型包裹，即T
type NakedType<T> = T extends boolean ? "YES" : "NO"

type yesType = NakedType<true>  //YES
type noType = NakedType<string>  //NO

let no:NakedType<string> = 'NO'

// 类型参数被包裹的在元组内，即[T]
type WrappedType<T> = [T] extends [boolean] ? "YES" : "NO";

type yewType2 = WrappedType<true>  //YES
type noType2 = WrappedType<'aaa'>  //NO

type NonFunctionKeys<T> = {
  [P in keyof T]: T[P] extends Function ? never : P // 这里保留的value被替换为了key
}[keyof T]

type MixedProps = { 
  name: string; 
  setName: (name: string) => void 
};
type Keys = NonFunctionKeys<MixedProps>; // Expect: "name"

//在协变位置上同一类型变量的多个候选类型将会被推断为联合类型：
type Foo2<T> = T extends { a: infer U, b: infer U } ? U : never;
type t1 = Foo2<{ a: string, b: string }>;  // string
type t2 = Foo2<{ a: string, b: number }>;  // string | numbe

//在逆变位置上同一类型变量的多个候选类型将会被推断为交叉类型：
type Bar<T> = T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U : never;
type t3 = Bar<{ a: (x: string) => void, b: (x: string) => void }>;  // string
type t4 = Bar<{ a: (x: string) => void, b: (x: number) => void }>;  // string & number
